﻿namespace BathroomLocator.Services
{
	using System.Globalization;
	using System.Net;
	using System.ServiceModel;
	using System.ServiceModel.Activation;
	using System.ServiceModel.Web;
	using System.Web.Security;
	using BathroomLocator.Services.Infrastructure;
	using BathroomLocator.Services.MembershipWrappers;
	using BathroomLocator.Services.Models;

	[ServiceBehavior(IncludeExceptionDetailInFaults = false)]
	[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
	public class AuthenticationService : IAuthenticationService
	{
		private readonly IFormsAuthentication formsAuth;
		private readonly IMembershipService membershipService;
		private readonly RoleProvider roleProvider;

		public AuthenticationService()
			: this(new FormsAuthenticationService(), new AccountMembershipService(), new RoleProviderWrapper())
		{
		}

		public AuthenticationService(IFormsAuthentication formsAuth, IMembershipService membershipService, RoleProvider roleProvider)
		{
			this.formsAuth = formsAuth;
			this.membershipService = membershipService;
			this.roleProvider = roleProvider;
		}

		public string GenerateAuthToken(LoginModel login)
		{
			if ((login == null) || string.IsNullOrEmpty(login.UserName) || string.IsNullOrEmpty(login.Password))
			{
				throw new WebFaultException<string>("Invalid credentials.", HttpStatusCode.BadRequest);
			}

			if (this.membershipService.ValidateUser(login.UserName, login.Password))
			{
				var user = this.membershipService.GetUser(login.UserName);
				var ticket = new FormsAuthenticationTicket(user.UserName, false, int.MaxValue);
				var token = this.formsAuth.Encrypt(ticket);

				return token;
			}

			return string.Empty;
		}

		public string ValidateAuthToken(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				throw new WebFaultException<string>("Token cannot be null or empty.", HttpStatusCode.BadRequest);
			}

			var ticket = this.formsAuth.Decrypt(token);
			if (ticket != null)
			{
				return ticket.Name;
			}

			return null;
		}

		public string CreateUser(CreateUserModel data)
		{
			if ((data == null) || string.IsNullOrEmpty(data.UserName) || string.IsNullOrEmpty(data.EMail) || string.IsNullOrEmpty(data.Password))
			{
				throw new WebFaultException<string>("Invalid user information.", HttpStatusCode.BadRequest);
			}

			var createStatus = this.membershipService.CreateUser(data.UserName, data.Password, data.EMail);
			if (createStatus == MembershipCreateStatus.Success)
			{
				this.SetUserDefaultPermissions(data.UserName);
			}

			return createStatus.ToString();
		}

		private void SetUserDefaultPermissions(string userName)
		{
			string[] users = { userName };

			this.AddPermissionsToTables(users);

			this.AddPermissionsToBlobs(users);

			this.AddTablePermission("SampleData", userName);
		}

		private void AddPermissionsToTables(string[] users)
		{
			string[] tableRoles = { RoleConstants.TablesUsageRole };
			this.roleProvider.AddUsersToRoles(users, tableRoles);
		}

		private void AddPermissionsToBlobs(string[] users)
		{
			string[] blobsRoles = { RoleConstants.BlobsUsageRole };
			this.roleProvider.AddUsersToRoles(users, blobsRoles);
		}

		private void AddTablePermission(string table, string user)
		{
			var tableRole = string.Format(CultureInfo.InvariantCulture, "{0}{1}", table, RoleConstants.TableRoleSuffix);
			if (!this.roleProvider.RoleExists(tableRole))
			{
				this.roleProvider.CreateRole(tableRole);
			}

			string[] users = { user };
			string[] roles = { tableRole };

			this.roleProvider.AddUsersToRoles(users, roles);
		}
	}
}